<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>组合函数的封装</title>
  <!-- 
  在JavaScript中，组合函数（Function Composition）是一种将多个函数组合成一个新函数的技术。这种方式允许开发者将多个小的、专注的函数组合成一个更复杂的函数，从而实现更简洁和可读的代码。
  一、组合函数的定义
  组合函数是指将多个函数连接起来，使得一个函数的输出可以作为下一个函数的输入。通常用符号“∘”表示组合操作，即  `f(g(x))` 。

  二、组合函数的优势
  1. 提高可读性：
    - 通过将多个小函数组合成一个大函数，代码的意图变得更加清晰。

  2. 增强复用性：
    - 组合函数使得小函数可以在不同的上下文中复用，从而减少代码重复。

  3. 简化复杂逻辑：
    - 将复杂的逻辑拆分为多个简单的函数，使得调试和维护变得更加容易。

  三、组合函数的实现

  以下是一个简单的组合函数的实现示例：

   示例：
  // 函数组合的实现
  function compose(...fns) {
      return function (initialValue) {
          return fns.reduceRight((accumulator, fn) => fn(accumulator), initialValue);
      };
  }

  // 示例函数
  const addOne = x => x + 1;
  const multiplyByTwo = x => x * 2;
  const square = x => x * x;

  // 组合函数
  const combinedFunction = compose(square, multiplyByTwo, addOne);
  console.log(combinedFunction(2)); // 输出: 36
  // 计算过程：
  // 1. addOne(2) => 3
  // 2. multiplyByTwo(3) => 6
  // 3. square(6) => 36

  四、使用场景
  1. 数据处理：
    - 在数据转换和处理的场景中，组合函数可以将多个转换步骤串联起来，使得数据流动更加清晰。

  2. 中间件：
    - 在构建中间件（如 Express.js 中间件）时，组合函数可以将多个处理函数组合成一个处理流程。

  3. React 组件：
    - 在 React 中，可以通过组合函数来增强组件的功能，例如使用高阶组件（HOC）模式。

  五、总结
  组合函数是将多个函数连接成一个新函数的强大技术，能够提高代码的可读性和可维护性。通过实现组合函数，开发者可以将复杂的逻辑拆分为多个简单的函数，并在需要时进行组合，从而实现灵活的代码结构。
  -->
</head>
<body>

  <script>
   
    // 1. 数字
    function addOne(x) {
      return x + 1;
    }

    function multiplyByTwo(x) {
      return x * 2;
    }

    function pow(x) {
      return x ** 2;
    }

    // 2. 字符串
    function toUpperCase(str) {
      return str.toUpperCase();
    }

    function addExclamation(str) {
      return str + '!';
    }

    // 3. 数组
    function filterEven(arr) {
      return arr.filter(x => x % 2 === 0);
    }

    function mapSquare(arr) {
      return arr.map(x => x ** 2);
    }

    // 4. 对象
    function addProperty(obj, key, value) {
      return { ...obj, [key]: value };
    }

    function removeProperty(obj, key) {
      const { [key]: _, ...rest } = obj;
      return rest;
    }

    // 5. 函数
    function compose(...funcs) {
      return function (x) {
        return funcs.reduce((acc, func) => func(acc), x);
      };
    }

    const composedFunction = compose(addOne, multiplyByTwo, pow);
    console.log(composedFunction(2)); // 18

    const composedFunction2 = compose(toUpperCase, addExclamation);
    console.log(composedFunction2('hello')); // HELLO!

    const composedFunction3 = compose(filterEven, mapSquare);
    console.log(composedFunction3([1, 2, 3, 4, 5])); // [4, 16]

    const composedFunction4 = compose(addProperty, removeProperty);
    console.log(composedFunction4({ a: 1, b: 2 }, 'b')); // { a: 1 }

    // 6. 封装的函数: 你传入多个函数, 我自动的将多个函数组合在一起挨个调用
    function composeFn(...fns) {
      // 1. 边界判断(edge case)
      const length = fns.length;
      if (length <= 0) return
      for (let i = 0; i < length; i++) {
        const fn = fns[i];
        if (typeof fn !== 'function') {
          throw new Error(`index position ${i} must be function`)
        }
      }

      // 2. 返回新函数
      return function (...args) {
        let result = fns[0].apply(this, args);
        
        for (let i = 1; i < length; i++) {
          const fn = fns[i];
          console.log(fns[i]);
          result = fn.apply(this, [result]);
        }
        return result;
      }
    }

    var newFn = composeFn(multiplyByTwo, pow, console.log)
    newFn(100)
    newFn(55)
    newFn(22)

  </script>
  
</body>
</html>